/*+********************************************************************
Filename: mux_2x3.v
Description: Implement 2 Host 3 Device with device bus addr starts with 0x0, 0x1, 0x2
Modification:
2024.02.06 creation  by H.Zheng

********************************************************************-*/

`define INVALID_DATA  32'h9abcdef9

module mux_2x3(

    // host 0 interface, for connection to JTAG 
    input wire[31:0] h0_addr_i,
    input wire[31:0] h0_data_i,
    output wire[31:0] h0_data_o,
    input wire h0_req_i,
    input wire h0_we_i,

    // host 1 interface, for connection to core
    input wire[31:0] h1_addr_i,
    input wire[31:0] h1_data_i,
    output wire[31:0] h1_data_o,
    input wire h1_req_i,
    input wire h1_we_i,

    // device 0 interface, for connection to rom port a
    output wire[31:0] d0_addr_o,
    output wire[31:0] d0_data_o,
    input wire[31:0] d0_data_i,
    output wire d0_we_o,
    output wire d0_ce_o,

    // device 1 interface, for connection to peripheral
    output wire[31:0] d1_addr_o,
    output wire[31:0] d1_data_o,
    input wire[31:0] d1_data_i,
    output wire d1_we_o,
    output wire d1_ce_o,

    // device, 2 interface, for connection to ram port a
    output wire[31:0] d2_addr_o,
    output wire[31:0] d2_data_o,
    input wire[31:0] d2_data_i,
    output wire d2_we_o,
    output wire d2_ce_o,

    //core load/store bus hold flag
    output wire h1_hold_flag_o

    );

    //control signals
    wire h0d0 = h0_req_i & (h0_addr_i[31:28] == 4'b0000);
    wire h0d1 = h0_req_i & (h0_addr_i[31:28] == 4'b0001);
    wire h0d2 = h0_req_i & (h0_addr_i[31:28] == 4'b0010);
    wire h1d0 = h1_req_i & (h1_addr_i[31:28] == 4'b0000);
    wire h1d1 = h1_req_i & (h1_addr_i[31:28] == 4'b0001);
    wire h1d2 = h1_req_i & (h1_addr_i[31:28] == 4'b0010);  //actually, core can not access ram through mux

    //hold core only when conflict occurs
    wire conflict0 = h0d0 & h1d0;
    wire conflict1 = h0d1 & h1d1;
    wire conflict2 = h0d2 & h1d2;

    assign h1_hold_flag_o = conflict0 | conflict1;

    //host 0
    assign h0_data_o = h0d0 ? d0_data_i :
                       h0d1 ? d1_data_i :
                       h0d2 ? d2_data_i : `INVALID_DATA;

    //host 1
    assign h1_data_o = h1d0 ? d0_data_i :
                       h1d1 ? d1_data_i :
                       h1d2 ? d2_data_i : `INVALID_DATA;

    //device 0: rom
    assign d0_addr_o = h0d0 ? h0_addr_i :
                       h1d0 ? h1_addr_i : `INVALID_DATA;
    assign d0_data_o = h0d0 ? h0_data_i :
                       h1d0 ? h1_data_i : `INVALID_DATA;
    assign d0_ce_o = h0d0 | h1d0;
//    assign d0_we_o = h0d0 ? h0_we_i :
//                     h1d0 ? h1_we_i : 1'b0;
    assign d0_we_o = h0d0 ? h0_we_i : 1'b0;  //core is not allowed to write rom

   //device 1: peripheral
    assign d1_addr_o = h0d1 ? h0_addr_i :
                       h1d1 ? h1_addr_i : `INVALID_DATA;
    assign d1_data_o = h0d1 ? h0_data_i :
                       h1d1 ? h1_data_i : `INVALID_DATA;
    assign d1_ce_o = h0d1 | h1d1;
    assign d1_we_o = h0d1 ? h0_we_i :
                     h1d1 ? h1_we_i : 1'b0;

   //device 2: ram, core does not access ram through bus mux
    assign d2_addr_o = h0d2 ? h0_addr_i : `INVALID_DATA;
    assign d2_data_o = h0d2 ? h0_data_i : `INVALID_DATA;
    assign d2_ce_o = h0d2;
    assign d2_we_o = h0d2 ? h0_we_i : 1'b0;


endmodule
